<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Marginalia Unit Tests</title>
<link rel="stylesheet" type="text/css" href="../css/jsUnitStyle.css">
<script language="JavaScript" type="text/javascript" src="../app/jsUnitCore.js"></script>
<script type="text/javascript" src="../../marginalia/log.js"></script>
<script type="text/javascript" src="../../marginalia/html-model.js"></script>
<script type="text/javascript" src="../../marginalia/domutil.js"></script>
<script type="text/javascript" src="../../marginalia/ranges.js"></script>
<script type="text/javascript" src="../../marginalia/SequenceRange.js"></script>
<script type="text/javascript" src="../../marginalia/XPathRange.js"></script>
<script language="javaScript" type="text/javascript">

function myload()
{
	window.log = new ErrorLogger( true, true );
	window.log.setTrace( 'WordRange', true );			// Check if quote matches current state of document
}

function makeXPathRange( sequenceStr )
{
	var root = document.getElementById( 'xpath-data' );

	var sequenceRange = new SequenceRange( sequenceStr );
	assertTrue( 'test sequence range parse', sequenceRange.toString() == sequenceStr );
	
	var wordRange = new WordRange( );
	wordRange.fromSequenceRange( sequenceRange, root );
	sequenceRange = wordRange.toSequenceRange( root );
	assertTrue( 'sequence range = ' + sequenceRange.toString() + ', expect ' + sequenceStr, sequenceRange.toString() == sequenceStr );
	
	return {
		root:  root,
		wordRange: wordRange,
		xpathRange: wordRange.toXPathRange( root )
	};
}

function testXPathRangeWithId( )
{
	var ranges = makeXPathRange( '/1/1/3.0;/1/1/3.2' );
	xpath = ranges.xpathRange.toString( );
	var expect = ".//*[@id='xbq1']/word(3)/char(0);.//*[@id='xbq1']/word(3)/char(2)";
	assertTrue( 'xpath ' + xpath + ' = expect ' + expect, xpath == expect );
	
	var wordRange = new WordRange( );
	wordRange.fromXPathRange( ranges.xpathRange, ranges.root );
	assertTrue( 'Test xpath range with ID resolution', wordRange.equals( ranges.wordRange ) );
}

function testXPathRangeFollowingId( )
{
	var ranges = makeXPathRange( '/1/2/2.0;/1/2/2.4' );
	xpath = ranges.xpathRange.toString( );
	var expect = ".//*[@id='xbq1']/following-sibling::blockquote[1]/word(2)/char(0);.//*[@id='xbq1']/following-sibling::blockquote[1]/word(2)/char(4)";
	assertTrue( 'xpath ' + xpath + ' = expect ' + expect, xpath == expect );
	
	var wordRange = new WordRange( );
	wordRange.fromXPathRange( ranges.xpathRange, ranges.root );
	assertTrue( 'Test xpath range with ID resulotion', wordRange.equals( ranges.wordRange ) );
}

function testRangeConversion( )
{
	var rel = document.getElementById( 'word-data' );

	/* t format below is:  elementid.childindex.charoffset */
	var conversionData = [
		{ t: 'li1.1.28;li2.1.4',	s: '/6/1/7.0;/6/2/1.2',	q: "hand: Lo",		c: 'crossing breaking element boundary'	},
		{ t: 'p5.1.5;em4.1.4',		s: '/5/2.0;/5/2.7',			q: 'brillig',		c: '5 chars in, then start tag, with <= 5 chars to go'			},
		{ t: 'p1.1.0;p1.1.1',		s: '/1/1.0;/1/1.1',			q: 'o',				c: 'first character'			},
		{ t: 'p1.1.0;p1.1.3',		s: '/1/1.0;/1/1.3',			q: 'one',			c: 'word alone in block'		},
		{ t: 'p2.1.0;p2.1.5',		s: '/2/1.0;/2/1.3',			q: 'two',			c: 'following space'			},
		{ t: 'p2.1.5;p2.1.10',		s: '/2/2.0;/2/2.5',			q: 'three',			c: 'spaces'						},
		{ t: 'p3.1.0;p3.1.6',		s: '/3/1.0;/3/1.4',			q: 'four',			c: 'spaces at either end'		},
		{ t: 'em1.1.0;em1.1.4',	s: '/3/2.0;/3/2.4',			q: 'five',			c: 'non-breaking element'		},
		{ t: 'p3.1.6;em1.1.4',		s: '/3/2.0;/3/2.4',			q: 'five',			c: 'cross em start boundary'	},
		{ t: 'em1.1.0;p3.3.0',		s: '/3/2.0;/3/2.4',			q: 'five',			c: 'cross em end boundary'		},
		{ t: 'em2.1.0;em3.1.5',	s: '/4/1.0;/4/1.10',		q: 'sevenseven',	c: 'cross em end/start'		},
		{ t: 'p1.1.0;p2.1.4',		s: '/1/1.0;/2/1.3',			q: 'one two',		c: 'span paragraphs'			},
		{ t: 's1.1.0;s1.1.3',		s: '/6/4/6.0;/6/4/6.3',	q: 'And',			c: 'from preceding nested element'	},
		{ t: 's1.1.0;s2.1.3',		s: '/6/4/6.0;/7/1.3',		q: 'And while in uffish thought he stood The',		c: 'cross BR tag'				}
	];

	for ( var i = 0;  i < conversionData.length;  ++i )
	{
		var conv = conversionData[ i ];

		conv.textRange = new TextRange( );
		conv.textRange.fromString( conv.t );
		conv.sequenceRange = new SequenceRange( conv.s );
		
		// TestWord Range -> TextRange conversion
		var wordRange = new WordRange( );			
		wordRange.fromTextRange( conv.textRange, rel, null );
		var sequenceRange = wordRange.toSequenceRange( rel ); 
		inform( conv.t + ' converts to ' + sequenceRange.toString( ) );
		assertTrue( 'Convert ' + conv.t + ' to ' + conv.s,
			conv.sequenceRange.equals( sequenceRange ) );
		
		// Test TextRange -> WordRange conversion
		wordRange.fromSequenceRange( conv.sequenceRange, rel, null );
		textRange = new TextRange( );
		textRange.fromWordRange( wordRange );
		var wordRange2 = new WordRange( );
		wordRange2.fromTextRange( conv.textRange, rel, null );
		assertTrue( 'Convert ' + conv.s + ' to ' + conv.t,
			wordRange.equals( wordRange2 ) );
			
		// Test range partition
		var parts = wordRange.partition( );
		var actual = parts.quote.replace( /\s+|\u00a0\s*/g, ' ' );
		var quote = conv.q.replace( /\s+|\u00a0\s*/g, ' ' );
		assertTrue( 'Range ' + conv.s + ' actual quote "' + actual + '" == expected "' + quote + '"', actual == quote );
	}
}

function testSequencePointOrder( )
{
	var r1 = new SequencePoint( '/2/3/4.5' );
	var r2 = new SequencePoint( '/2/3/4.6' );
	var r3 = new SequencePoint( '/2/3/3.5' );
	var r4 = new SequencePoint( '/2/4/3.2' );
	var r5 = new SequencePoint( '/3/2/2.1' );
	var r6 = new SequencePoint( '/2/4.6' );
	var r7 = new SequencePoint( '/2/3' );
	var r8 = new SequencePoint( '/2/4' );
	
	assertTrue( r1.compare( r1 ) == 0 );
	assertTrue( r1.compare( r2 ) < 0 );
	assertTrue( r2.compare( r1 ) > 0 );
	assertTrue( r1.compare( r3 ) > 0 );
	assertTrue( r1.compare( r4 ) < 0 );
	assertTrue( r1.compare( r5 ) < 0 );
	assertTrue( r7.compare( r8 ) < 0 );
}

function testSequenceRangeOrder( )
{
	var r1 = new SequenceRange( '/2/3.0;/2/3.4' );
	var r2 = new SequenceRange( '/2/3.1;/2/3.2' );
	var r3 = new SequenceRange( '/2/3.0;/2/3.5' );
	var r4 = new SequenceRange( '/2/2.5;/2/2.6' );
	var r5 = new SequenceRange( '/2/2.5;/2/4.5' );
	var r6 = new SequenceRange( '/3/2.0;/3/2.1' );
	
	assertTrue( r1.compare( r1 ) == 0 );
	assertTrue( r1.compare( r2 ) < 0 );
	assertTrue( r1.compare( r3 ) < 0 );
	assertTrue( r1.compare( r4 ) > 0 );
	assertTrue( r1.compare( r5 ) > 0 );
	assertTrue( r1.compare( r6 ) < 0 );
}

TextRange.prototype.fromString = function( str )
{
	var points = str.split( ';' );
	
	// Get the start point
	var parts = points[ 0 ].split( '.' );
	var element = document.getElementById( parts[ 0 ] );
	var childIndex = Number( parts[ 1 ] ) - 1;
	this.startContainer = element.childNodes[ childIndex ];
	this.startOffset = Number( parts[ 2 ] )
	
	// Get the end point
	parts = points[ 1 ].split( '.' );
	element = document.getElementById( parts[ 0 ] );
	childIndex = Number( parts[ 1 ] ) - 1;
	this.endContainer = element.childNodes[ childIndex ];
	this.endOffset = Number( parts[ 2 ] );
}
</script>
</head>

<body onload='myload()'>
<h1>Marginalia Range Format Conversion Tests</h1>

<button onclick="testRangeConversion()">Run Test</button>

<div id="word-data">
<p id="p1">one</p>
<p id="p2"> two three  </p>
<p id="p3"> four <em id="em1">five</em> six </p>
<p id="p4"> <em id="em2">seven</em><em id="em3">seven</em> </p>
<p id="p5">Twas bri<em id="em4" class="annotation annot3 last">llig,</em> and the slithy toves</p>
<ul id="ul1">
<li id="li1">He took his vorpal sword in hand:</li>
<li id="li2">  Long time the manxome foe he sought --</li>
<li id="li3">So rested he by the Tumtum tree,</li>
<li id="li4">  And stood awhile in thought.</li>
</ul>
<span id="s1">And while in uffish thought he stood</span><br id="br1"
/><span id="s2">The Jabberwock, with eyes of flame, came wiffling through the tulgey wood.</span>
</div>

<div id="xpath-data">
<div id="xdiv1">"Beware <blockquote id="xbq1">the <span id="xspan1">Jabberwock, my son!</span>
  The </blockquote>jaws that bite,<blockquote> the claws that catch!</blockquote>
Beware the Jubjub bird, and shun
  The frumious Bandersnatch!"</div>
</div>

</body>
</html>
